#include <stdio.h>
#include <stdlib.h>

#include "../../libs/Utils/Utils.h"
#include "../../libs/SparceMatrix/sparse_matrix.h"
#include "../../libs/SparceMatrix/LinearIO.h"
#include "../../libs/PowerMethod/Computations.h"
#include "../../libs/Containers/NumListIO.h"
#include "../../libs/Containers/Utils.h"
#include "../../libs/LinearComputation/Vector.h"
#include "../../libs/LinearComputation/Matrix.h"
#include "../../libs/LinearComputation/ModularityMatrix.h"

int main(int argv, char* argc[])
{
	sparse_matrix_lst* adjMatrix = NULL, *partialAdjMatrix = NULL;
	NumList * group = NULL;
	ListOfNumList* spectralProduct = NULL;
	elem precision = 0;
	elem* degVector = NULL, *partialDegVec = NULL, *groupVec,
		* modularityMat = NULL, * fVec = NULL, *deltaQ;
	bool ret = TRUE;
	
	TAssertM(argv >= 4, "Not enough arguments.");
	TAssert(MemoryAssert(1, deltaQ = (elem*)malloc(sizeof(elem))));

	*deltaQ = 0;

	if (NULL == (adjMatrix = ReadInMatrix(argc[1]))
			||NULL == (group = ReadNumList(argc[2]))
			|| 1 != sscanf(argc[3], "%lf", &precision)
			|| NULL == (degVector = DegVector(adjMatrix, 
					(elem*)malloc(sizeof(elem) * adjMatrix->n)))
			|| NULL == (partialDegVec = PartialVector(degVector, group))
			|| NULL == (partialAdjMatrix = PartialMatrix(adjMatrix, group))
			|| NULL == (modularityMat = CreateModularityMatrix(adjMatrix, group))
			|| NULL == (fVec = VectorOfRowSums(modularityMat, 
					(elem*)malloc(sizeof(elem)*(group->size)), group->size))
			|| NULL == (groupVec = SpectricalDiv(partialAdjMatrix,
					partialDegVec, modularityMat, fVec,	precision, 
					SumOfVector(degVector, adjMatrix->n), group->size, deltaQ)))
		ret = FALSE;

	if ((spectralProduct = SplitNumList(group, groupVec)) == NULL)
		ret = FALSE;
	

	if(ret)
	{
		if (spectralProduct->size != 2)
			ret = FALSE;
		else
		{
			ret = printf("%lf\n", *deltaQ) >= 0;
			if (ret && spectralProduct->value->next != NULL)
				ret = PrintNumList(spectralProduct->value);
			if (ret && spectralProduct->next->value->next != NULL)
				ret = printf("\n") 
					&& PrintNumList(spectralProduct->next->value);
		}
	}
	
	MemoryAssert(6, NULL, degVector, partialDegVec, modularityMat, fVec, deltaQ);
	free_sparse_matrix_lst(adjMatrix);
	free_sparse_matrix_lst(partialAdjMatrix);
	DeleteNumList(group);
	DeleteListOfNumList(spectralProduct, TRUE);
	
	return !ret; //Successful = 0 = FALSE = !TRUE
}
